// @ts-nocheck
import { lowlight } from 'lowlight';
import React,{ useEffect, useRef, useState } from 'react';
import css from 'highlight.js/lib/languages/css'
import js from 'highlight.js/lib/languages/javascript'
import ts from 'highlight.js/lib/languages/typescript'
import html from 'highlight.js/lib/languages/xml'
import python from 'highlight.js/lib/languages/python';
import java from 'highlight.js/lib/languages/java';
import c from 'highlight.js/lib/languages/c';
import cpp from 'highlight.js/lib/languages/cpp';
import csharp from 'highlight.js/lib/languages/csharp';
import ruby from 'highlight.js/lib/languages/ruby';
import php from 'highlight.js/lib/languages/php';
import go from 'highlight.js/lib/languages/go';
import swift from 'highlight.js/lib/languages/swift';
import kotlin from 'highlight.js/lib/languages/kotlin';
import scala from 'highlight.js/lib/languages/scala';
import dart from 'highlight.js/lib/languages/dart';
import rust from 'highlight.js/lib/languages/rust';
import sql from 'highlight.js/lib/languages/sql';
import markdown from 'highlight.js/lib/languages/markdown';
import {ToC} from '../ToC'

// Register the languages with lowlight
lowlight.registerLanguage('html', html)
lowlight.registerLanguage('css', css)
lowlight.registerLanguage('js', js)
lowlight.registerLanguage('ts', ts)
lowlight.registerLanguage('python', python);
lowlight.registerLanguage('java', java);
lowlight.registerLanguage('c', c);
lowlight.registerLanguage('cpp', cpp);
lowlight.registerLanguage('csharp', csharp);
lowlight.registerLanguage('ruby', ruby);
lowlight.registerLanguage('php', php);
lowlight.registerLanguage('go', go);
lowlight.registerLanguage('swift', swift);
lowlight.registerLanguage('kotlin', kotlin);
lowlight.registerLanguage('scala', scala);
lowlight.registerLanguage('dart', dart);
lowlight.registerLanguage('rust', rust);
lowlight.registerLanguage('sql', sql);
lowlight.registerLanguage('markdown',markdown)

function jsonToHtml(json: any) {
    if (!json || !('type' in json)) {
        throw new Error("Invalid input: missing 'type' property");
    }

    switch (json.type) {
        case 'text':
            return json.value;
        case 'element': {
            const attributes = Object.entries(json.properties)
                .filter(([key, value]) => key !== 'className')
                .map(([key, value]) => `${key}="${value}"`)
                .join(' ');
            const classNames = json.properties?.className?.join(' ') ?? '';

            const openTag = `<${json.tagName} ${classNames ? `class="${classNames}"` : ''} ${attributes}>`;
            const closeTag = `</${json.tagName}>`;

            const childrenHtml = (json.children ?? []).map(jsonToHtml).join('');

            return `${openTag}${childrenHtml}${closeTag}`;
        }
        case 'root':
            return (json.children ?? []).map(jsonToHtml).join('');
        default:
            throw new Error(`Unsupported node type: ${json.type}`);
    }
}
const MemorizedToC = React.memo(ToC)

function CodeHighlighter({ htmlString,style,items=[] }:{htmlString:string,style?:CSSProperties;items?:any}) {
    const [highlightedHtml, setHighlightedHtml] = useState(htmlString);
    const ref:any = useRef(null);

    useEffect(() => {
        const codeBlocks = ref.current.querySelectorAll('pre code');
        codeBlocks.length && codeBlocks.forEach((codeBlock) => {
            const language = codeBlock.className.replace(/language-/, '');
            const auto = lowlight.highlightAuto(codeBlock.textContent);
            const highlightedTokens = language ? lowlight.highlight(language, codeBlock.textContent) : auto.data.language ? auto : lowlight.highlight('markdown', codeBlock.textContent);
            codeBlock.innerHTML = jsonToHtml(highlightedTokens);
        });
        setHighlightedHtml(ref.current.innerHTML);
    }, [ref.current]);
    useEffect(() => {
        setHighlightedHtml(htmlString)
    }, [htmlString]);

    return <div>
        {items.length !== 0&&<div className="table-of-content">
        <MemorizedToC items={items} />
      </div>}
        <div ref={ref} style={{...style,paddingRight: items.length&&'24rem'}} dangerouslySetInnerHTML={{ __html: highlightedHtml }} />
    </div>;
}

export default CodeHighlighter;